LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;

-- addbuff3
-- like a bau5

ENTITY addbuff3 IS
   PORT(
       clk, reset :  IN STD_LOGIC;     -- clk
       TBL_to_FWD_ACK : IN STD_LOGIC;
       OMX_to_ARB_Done : IN STD_LOGIC;
       portChoice : IN STD_LOGIC_VECTOR(1 DOWNTO 0); -- portChoice, the source port
       portvalid: IN STD_LOGIC; -- portReady
	   des_mux0, des_mux1,des_mux2,des_mux3 : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- desAddress0
	   src_mux0, src_mux1,src_mux2,src_mux3: IN STD_LOGIC_VECTOR(7 DOWNTO 0);  -- srcAddress0
	   clkout, resetout :  OUT STD_LOGIC;     -- clk
       portChoiceout : OUT STD_LOGIC_VECTOR(1 DOWNTO 0); -- portChoice
       portvalidout: OUT STD_LOGIC; -- portReady
	   des_mux0out: OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- desAddress0
	   src_mux0out: OUT STD_LOGIC_VECTOR(7 DOWNTO 0);  -- srcAddress0
	   WE_READY: OUT STD_LOGIC; -- ACK polling the table
	   src_ready0, src_ready1, src_ready2, src_ready3 : IN STD_LOGIC; -- sendingsrcAddress0
	   des_ready0, des_ready1, des_ready2, des_ready3 : IN STD_LOGIC; -- sendingdesAddress0
	   srcPort : OUT STD_LOGIC_VECTOR(1 DOWNTO 0);	  -- FWD_to_TBL_srcPort
	   srcAddress : OUT STD_LOGIC_VECTOR(47 DOWNTO 0);-- FWD_to_TBL_srcAddress
	   desAddress : OUT STD_LOGIC_VECTOR(47 DOWNTO 0); -- FWD_to_TBL_desAddress
	   bufferDone0, bufferDone1, bufferDone2, bufferDone3 : IN STD_LOGIC -- Can we assume we're done if we have an empty buffer?
       );
END addbuff3;



ARCHITECTURE addbuff3_arch OF addbuff3 IS

COMPONENT aggregator IS
   PORT(
	   clk, reset : IN STD_LOGIC;
	   incomingdata : IN STD_LOGIC;
	   data_in : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
	   outputs_ready : OUT STD_LOGIC;
	   Address : OUT STD_LOGIC_VECTOR(47 DOWNTO 0)
       );
END COMPONENT;

COMPONENT addbuff3MUX IS
	PORT
	(
		data0x		: IN STD_LOGIC_VECTOR (47 DOWNTO 0);
		data1x		: IN STD_LOGIC_VECTOR (47 DOWNTO 0);
		data2x		: IN STD_LOGIC_VECTOR (47 DOWNTO 0);
		data3x		: IN STD_LOGIC_VECTOR (47 DOWNTO 0);
		sel		: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
		result		: OUT STD_LOGIC_VECTOR (47 DOWNTO 0)
	);
END COMPONENT;

COMPONENT TestFF IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		sclr		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END COMPONENT;

COMPONENT addbuff3FF IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (1 DOWNTO 0)
	);
END COMPONENT;

COMPONENT addbuff3portFF IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (1 DOWNTO 0)
	);
END COMPONENT;

SIGNAL src0ready, src1ready, src2ready, src3ready : STD_LOGIC;
SIGNAL des0ready, des1ready, des2ready, des3ready : STD_LOGIC;
SIGNAL srcAddress0, srcAddress1, srcAddress2, srcAddress3 : STD_LOGIC_VECTOR(47 DOWNTO 0);
SIGNAL desAddress0, desAddress1, desAddress2, desAddress3 : STD_LOGIC_VECTOR(47 DOWNTO 0);
SIGNAL reset0, reset1, reset2, reset3 : STD_LOGIC;
SIGNAL prevport : STD_LOGIC_VECTOR(1 DOWNTO 0);
SIGNAL src_is_ready : STD_LOGIC;
SIGNAL sportChoice : STD_LOGIC_VECTOR(1 DOWNTO 0);
SIGNAL metaportChoice : STD_LOGIC;

BEGIN
clkout<=clk;
resetout<=reset; 
portChoiceout<=portChoice; 
portvalidout<=portvalid;
des_mux0out<=des_mux0;
src_mux0out<=src_mux0;
-- When I'm receiving data, I need to hold onto it from four ports.
-- Best of all, none of these need to be flushed. Data will just be pushed through.
aggregatebuffer0srcAddress: aggregator PORT MAP(clk, reset, src_ready0, src_mux0, src0ready, srcAddress0);
aggregatebuffer0desAddress: aggregator PORT MAP(clk, reset, des_ready0, des_mux0, des0ready, desAddress0);
aggregatebuffer1srcAddress: aggregator PORT MAP(clk, reset, src_ready1, src_mux1, src1ready, srcAddress1);
aggregatebuffer1desAddress: aggregator PORT MAP(clk, reset, des_ready1, des_mux1, des1ready, desAddress1);
aggregatebuffer2srcAddress: aggregator PORT MAP(clk, reset, src_ready2, src_mux2, src2ready, srcAddress2);
aggregatebuffer2desAddress: aggregator PORT MAP(clk, reset, des_ready2, des_mux2, des2ready, desAddress2);
aggregatebuffer3srcAddress: aggregator PORT MAP(clk, reset, src_ready3, src_mux3, src3ready, srcAddress3);
aggregatebuffer3desAddress: aggregator PORT MAP(clk, reset, des_ready3, des_mux3, des3ready, desAddress3);

-- Always spam what I've got thus far:
Latching_the_Port_Choice: addbuff3portFF PORT MAP(reset, clk, portChoice, portvalid, sportChoice); 

SpamSrcAddress: addbuff3MUX PORT MAP(srcAddress0, srcAddress1, srcAddress2, srcAddress3, sportChoice, srcAddress);
SpamDesAddress: addbuff3MUX PORT MAP(desAddress0, desAddress1, desAddress2, desAddress3, sportChoice, desAddress);
srcPort <= sportChoice;

-- src_is_ready indicates that bytes of the address are now being passed into the aggregators.
-- 
src_is_ready <= (src_ready0 AND NOT (sportChoice(1) OR sportChoice(0))) OR (src_ready1 AND NOT sportChoice(1) AND sportChoice(0)) OR 
                (src_ready2 AND sportChoice(1) AND NOT sportChoice(0)) OR (src_ready3 AND sportChoice(1) AND sportChoice(0));

-- We're ready to begin passing data to the table if
-- 1.) The port that the arbiter sent us is valid (portvalid)
-- 2.) We've received enough bytes of data to have valid addresses (src_is_ready)
-- 3.) There is data to be sent from the buffer (bufferDoneX AND XX)
		
		
		
LatchThisCrap: TestFF PORT MAP (reset, clk, (portvalid OR metaportChoice) and not TBL_to_FWD_ACK, '0',  metaportChoice);

WE_READY <= metaportChoice;

--LatchThisCrap: TestFF PORT MAP ((reset OR NOT(portvalid)), clk, src_is_ready AND portvalid, WE_READY);


END addbuff3_arch;